package brickdestroyer.math;

/**
 * This class represents a vector in 2d cartesian
 * coordinate system.
 *
 * @author Momchil Atanasov
 */
public class Vector2D {

    /**
     * X coordinate of the vector in a Cartesian coordinate system.
     */
    public float x = 0.0f;

    /**
     * Y coordinate of the vector in a Cartesian coordinate system.
     */
    public float y = 0.0f;

    /**
     * Creates a vector object and initializes the coordinates
     * to (0.0f, 0.0f).
     */
    public Vector2D() {
    }

    /**
     * Creates a vector object and initialized the coordinates to
     * the ones passed as parameters.
     * @param x the X coordinate of the vector
     * @param y the Y coordinate of the vector
     */
    public Vector2D(float x, float y) {
        this.x = x;
        this.y = y;
    }

    /**
     * This is a copy-constructor.<br>
     * Creates a new vector object with the same coordinates as the
     * one passed as a parameter.
     * @param other vector to be copied.
     */
    public Vector2D(Vector2D other) {
        this(other.x, other.y);
    }

    /**
     * This method performs vector addition.
     * <p>Increases the value of this vector with the specified
     * <code>x</code> and <code>y</code> numbers.
     * @param x X coordinate of the vector to be added.
     * @param y Y coordinate of the vector to be added.
     */
    public void inc(float x, float y) {
        this.x += x;
        this.y += y;
    }

    /**
     * This method performs vector addition.
     * @param vector vector to be added to this one.
     */
    public void inc(Vector2D vector) {
        inc(vector.x, vector.y);
    }

    /**
     * This method is a convenience one. It performs a
     * vector addition without changing the value of this
     * vector and returns the result.
     * @param vector vector to be added.
     * @return the result of the addition
     */
    public Vector2D getInc(Vector2D vector) {
        Vector2D result = new Vector2D(this);
        result.inc(vector);
        return result;
    }

    /**
     * This method performs vector subtraction.
     * <p>It decreases the coordinates of this vector by the values
     * passed as parameters.
     * @param x X coordinate of the subtraction vector
     * @param y Y coordinate of the subtraction vector
     */
    public void dec(float x, float y) {
        this.x -= x;
        this.y -= y;
    }

    /**
     * This method performs vector subtraction.
     * @param vector vector by which to subtract.
     */
    public void dec(Vector2D vector) {
        dec(vector.x, vector.y);
    }

    /**
     * This method is a convenience one. It subtracts this vector
     * without modifying it by the one passed as parameter and
     * returns the result.
     * @param vector vector by which to subtract.
     * @return the result of the vector subtraction
     */
    public Vector2D getDec(Vector2D vector) {
        Vector2D result = new Vector2D(this);
        result.dec(vector);
        return result;
    }

    /**
     * This method multiplies this vector by the given value.
     * @param value multiplication value.
     */
    public void mul(float value) {
        x *= value;
        y *= value;
    }

    /**
     * This method performs direct vector multiplication.
     * <p>The <code>x</code> value of this vector gets multiplied by
     * the <code>x</code> vaue of the other vector and the same is
     * done to the <code>y</code> values.
     * @param vector
     */
    public void mul(Vector2D vector) {
        x *= vector.x;
        y *= vector.y;
    }

    /**
     * This is a convenience method which performs vector multiplication
     * by some value without modifying the current vector and returns the
     * result.
     * @param value value by which to multiply
     * @return result of the multiplication
     */
    public Vector2D getMul(float value) {
        Vector2D result = new Vector2D(this);
        result.mul(value);
        return result;
    }

    /**
     * This method divides the vector by some value.
     * @param value value by which to divide.
     */
    public void div(float value) {
        x /= value;
        y /= value;
    }

    /**
     * This method divides the vector by some other
     * vector.
     * @param vector vector by which to divide
     */
    public void div(Vector2D vector) {
        x /= vector.x;
        y /= vector.y;
    }

    /**
     * This method sets new coordinates of the vector.
     * @param x new X coordinate
     * @param y new Y coordinate
     */
    public void setTo(float x, float y) {
        this.x = x;
        this.y = y;
    }

    /**
     * This methods sets the same coordinates as the
     * ones of the vector being passed as parameter.
     * @param vector vector to be replicated.
     */
    public void setTo(Vector2D vector) {
        setTo(vector.x, vector.y);
    }

    /**
     * This method sets a new length to this vector.
     * @param length new length of the vector.
     */
    public void setLength(float length) {
        float currentLength = getLength();
        final float MARGIN = 0.0001f;
        if (currentLength < MARGIN) {
            return;
        }
       
        mul(length / currentLength);
    }

    /**
     * This method returns the squared length of this vector.
     * @return squared length of the vector
     */
    public float getLengthSqr() {
        return (x * x + y * y);
    }

    /**
     * This method returns the length of this vector.
     * @return length of the vector
     */
    public float getLength() {
        return (float)Math.sqrt(getLengthSqr());
    }

    /**
     * This method returns the dot product of this vector
     * and the one passed as parameter.
     * @param vector vector in the dot product function.
     * @return result of the dot product (x1 * x2 + y1 * y2).
     */
    public float dotProduct(Vector2D vector) {
        return (x * vector.x + y * vector.y);
    }
    
}
